/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.previewpicture.app;

import com.bumptech.glide.util.LogUtil;
import com.bumptech.glide.util.Synthetic;

import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.render.Texture;
import ohos.agp.utils.Matrix;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;

import org.jetbrains.annotations.NotNull;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * TransformationUtils.
 *
 * @author author
 * @version version
 */
public final class TransformationUtils {
    /**
     * TAG.
     */
    private static final String TAG = "TransformationUtils";
    /**
     * DEFAULT_PAINT.
     */
    private static Paint DEFAULT_PAINT = new Paint();

    static {
        DEFAULT_PAINT.setDither(true);
        DEFAULT_PAINT.setFilterBitmap(true);
    }

    private static final Lock BITMAP_DRAWABLE_LOCK = new NoLock();

    private TransformationUtils() {
    }

    private static void clear(Canvas canvas) {
        canvas.setTexture(null);
    }

    private static PixelFormat getNotNullConfig(PixelMap pixelMap) {
        return pixelMap.getImageInfo() != null ? pixelMap.getImageInfo().pixelFormat
                : PixelFormat.ARGB_8888;
    }

    private static void applyMatrix(
            PixelMap inBitmap, PixelMap targetBitmap, Matrix matrix) {
        BITMAP_DRAWABLE_LOCK.lock();
        try {
            Canvas canvas = new Canvas(new Texture(targetBitmap));
            //canvas.concat(matrix);
            LogUtil.info(TAG, " applyMatrix() and targetBitmap width is "
                    + targetBitmap.getImageInfo().size.width
                    + " targetBitmap height is "
                    + targetBitmap.getImageInfo().size.height);
            LogUtil.info(TAG, " applyMatrix() and inBitmap width is "
                    + inBitmap.getImageInfo().size.width
                    + " targetBitmap height is "
                    + inBitmap.getImageInfo().size.height);
            canvas.setMatrix(matrix);
            canvas.drawPixelMapHolder(new PixelMapHolder(inBitmap), 0, 0, DEFAULT_PAINT);
            clear(canvas);
        } finally {
            BITMAP_DRAWABLE_LOCK.unlock();
        }
    }

    /**
     * centerCrop.
     *
     * @param inBitmap inBitmap
     * @param width    width
     * @param height   height
     * @return PixelMap
     */
    public static PixelMap centerCrop(
            @NotNull PixelMap inBitmap, int width, int height) {
        if (inBitmap.getImageInfo().size.width == width && inBitmap.getImageInfo().size.height == height) {
            return inBitmap;
        }
        final float scale;
        final float dx;
        final float dy;
        Matrix matrix = new Matrix();
        if (inBitmap.getImageInfo().size.width * height >
                width * inBitmap.getImageInfo().size.height) {
            scale = (float) height / (float) inBitmap.getImageInfo().size.height;
            dx = (width - inBitmap.getImageInfo().size.width * scale) * 0.5f;
            dy = 0;
        } else {
            scale = (float) width / (float) inBitmap.getImageInfo().size.width;
            dx = 0;
            dy = (height - inBitmap.getImageInfo().size.height * scale) * 0.5f;
        }
        matrix.setScale(scale, scale);
        matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
        PixelMap result = createPixelmap(width, height, getNotNullConfig(inBitmap));
        // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
        TransformationUtils.setAlpha(inBitmap, result);
        applyMatrix(inBitmap, result, matrix);
        return result;
    }

    private static PixelMap createPixelmap(int width, int height, PixelFormat config) {
        PixelMap.InitializationOptions opts = new PixelMap.InitializationOptions();
        opts.size = new Size(width, height);
        opts.pixelFormat = config;
        return PixelMap.create(opts);
    }

    /**
     * setAlpha.
     *
     * @param inBitmap  inBitmap
     * @param outBitmap outBitmap
     */
    public static void setAlpha(PixelMap inBitmap, PixelMap outBitmap) {
        outBitmap.setAlphaType(inBitmap.getImageInfo().alphaType);
    }

    private static final class NoLock implements Lock {
        @Synthetic
        NoLock() {
        }

        @Override
        public void lock() {
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
        }

        @Override
        public boolean tryLock() {
            return true;
        }

        @Override
        public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
            return true;
        }

        @Override
        public void unlock() {
        }

        @NotNull
        @Override
        public Condition newCondition() {
            throw new UnsupportedOperationException("Should not be called");
        }
    }
}
